/*********************************************************************************
 *      Copyright:  (C) 2025 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  main.c
 *    Description:  This file project1_demo main.c
 *                 
 *        Version:  1.0.0(06/04/25)
 *         Author:  huangzixiao
 *      ChangeLog:  1, Release initial version on "06/04/25 15:22:56"
 *                 
 ********************************************************************************/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <netdb.h>

#include "logger.h"
#include "packet.h"
#include "../sqlite/sqlite3/include/sqlite3.h"
#include "ds18b20.h"
#include "sqlite.h"
#include "socket.h"



/* ****************************Function declaration****************************** */
void alarm_handler(int signum);
void printf_help(char *progname );


int alarm_flag = 0;

int main(int argc, char **argv)
{
	int					rv = 0;
	int                 i = 0;
	int					logger_level = 3;/* 0:errno 1:warn 2:info 3:debug 4: 5:max */
	char				pack_buf[1024] = {0};
	int					buf_len;

	/* ****************Variables required for packet*********** */
	pack_data_t			 data;
//	pack_proc_t          pack_proc = packet_segmented_pack; /* use segmented string packet */

	//pack_proc_t          pack_proc = packet_json_pack;      /* use JSON string packet */
    pack_proc_t          pack_proc = packet_tlv_pack;       /* use TLV(Tag Length Value) packet */


	/* ****************Variables required for sample*********** */
	unsigned int          alarm_time = 0;
	int                   sample_flag = 0;

	/* ****************Variables required for SQLite*********** */
	db_info_t             db_info = 
	{
		NULL,
		"../sqlite/local_sqlite.db",
		"sampling_data",
		NULL
	};
	callback_arg_t        callback_arg;//include "sqlite_have_data,upload_sqlite_data,
	int                   delete_db_data = 0;

	/* *****************Variables required for socket***************** */
	socket_info_t         socket_info = {0};
	struct                sockaddr_in servaddr;
	char                  upload_data[128] = {0};
	int                   reconnect_time = 1;

	
	/* ***************************Get argument********************************** */
	int                   opt = -1;
	struct   option       opt_long[] =
    {   
        {"alarm_time", required_argument, 0, 'a'},
        {"server_ip", required_argument, 0, 'i'},
        {"server_port", required_argument, 0, 'p'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
    };  

    while( (opt = getopt_long(argc, argv, "a:i:p:h", opt_long, NULL)) != -1 )
    {   

        switch(opt)
        {   
            case 'a':
                alarm_time = atoi(optarg);
                break;
   
			case 'i':
                socket_info.hostname = optarg;
                break;
            
			case 'p':
                socket_info.service = optarg;
                break;
            
			case 'h':
                printf_help(argv[0]);
                exit(0);
            
			default:
                break;
        }   
    }

	if(!socket_info.hostname || !socket_info.service || !alarm_time )
    {
        printf_help(argv[0]);
        exit(-1);
    }


    //logger init
    rv = log_open("console", logger_level, 0, LOG_LOCK_DISABLE);
    //rv = log_open("client.log", logger_level, 10, LOG_LOCK_DISABLE);
	if(rv < 0)
	{
		printf("logger system open failure:%s\n", strerror(errno));
		return -1;
	}


    log_info("\nserver_ip:%s/server_port:%s/alarm_time:%d\n",
			socket_info.hostname, socket_info.service, alarm_time);

	rv = db_init(&db_info);
	if(rv < 0)
	{
		log_error("db init failure\n");
		exit(-1);
	}
	log_debug("db init successfully\n");

	if( socket_connect(&socket_info) < 0 )
	{
		log_error("socket connect failure\n");
	}

	//ignore SIGPIPE
    if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
    {
        log_error("set SIGPIPE failure:%s\n", strerror(errno));
        exit(-1);
    }
	//Caught the SIGALRM signal, call the sampling function in the handler.
    if(signal(SIGALRM, alarm_handler) == SIG_ERR)
    {   
        log_error("set SIGALRM failure:%s\n", strerror(errno));
        exit(-1);
    } 
	alarm(alarm_time);
	log_debug("alarm init over, program starting...\n");

	while(1)
	{
		sample_flag = 0;

		/* ********************************sample module**************************** */
		if(alarm_flag)
		{
			memset(&data, 0, sizeof(data));
			memset(pack_buf, 0, sizeof(pack_buf));

			/*
			   Get data in the sampling function and assign the data to the data structure,
			   and set the sampling flag to '1' to indicate that sampling has been done.
			   */
			rv = sampling(&data);
			if(rv < 0)
			{
				log_error("sampling failure\n");
				sleep(1);
				continue;
			}
			log_debug("sampling successfully\n");

			buf_len = pack_proc(&data, (uint8_t *)pack_buf, sizeof(pack_buf));
			if(buf_len < 0)
			{
				log_error("packet data failure\n");
				sleep(1);
				continue;
			}

			if(pack_proc == packet_tlv_pack)
			{
				log_info("TLV header:0x%02X%02X, Tag:%d, Length:0x%02X%02X\n", 
						pack_buf[0], pack_buf[1], pack_buf[2], pack_buf[3], pack_buf[4]);
				//		*(uint16_t *)(pack_buf + 3));
				//pack_buf[3]=0x00为低字节, pack_buf[4]=0x10为高字节
				//设由一个变量uint16_t a=*(uint16_t *)(pack_buf + 3)接收结果
				//则赋值过程字节序变换：a[0]=0x00, a[1]=0x10; a=0x1000
				for(i=5; i<buf_len; i++)
				{
					if(i>=5 && i<13)
						log_info("pack_buf[%d](device):%c\n", i, pack_buf[i]);
					if(i>=13 && i<19)
						log_info("pack_buf[%d](time):%d\n", i, pack_buf[i]);
					if(i>=19 && i<21)
						log_info("pack_buf[%d](temperature):%d\n", i, pack_buf[i]);
					if(i == 21)
						log_info("CRC:0x%02X%02X\n", pack_buf[21], pack_buf[22]);
				}
			}
			else
				log_info("sampling %d data:%s\n", buf_len, pack_buf);

			sample_flag = 1;
			alarm_flag = 0;

			alarm(alarm_time);
		}

		/* ********************************communication module**************************** */
		if( socket_connected(&socket_info) != 1 )
		{
			sleep(reconnect_time);
			
			socket_connect(&socket_info);
			if(socket_connected(&socket_info) != 1) //if(socket_info.status < 0)?
			{
				if(sample_flag)
				{
					log_debug("insert data into SQLite\n");
					rv = save_in_db(&db_info, pack_buf, buf_len);
					if(rv < 0)
					{
						log_error("insert data into SQLite failure! data maybe lost!\n");
						continue;
					}
				}
				continue;
			}
			log_debug("reconnected successfully\n");
		}

		if(sample_flag)
		{
			rv = socket_send(&socket_info, pack_buf, buf_len);//疑惑,待review:snprintf自动加'\0'
			if(rv < 0)
			{
				log_error("write sampled data failure:'%s',ignore SIGPIPE,Now save the sampled data to SQLite! \n", strerror(errno));

				rv = save_in_db(&db_info, pack_buf, buf_len);
				if(rv < 0)
				{
					log_error("insert data into SQLite failure! data maybe lost!\n");
					continue;
				}
				continue;
			}
		}


		/* ***************if connecting check whether local SQLite have data************ */ 
		memset(pack_buf, 0, sizeof(pack_buf));
		rv = get_data_in_db(&db_info, pack_buf, sizeof(pack_buf), &buf_len);
		if(rv == 0)
		{
			log_debug("there is data in SQLite\n");
			delete_db_data = 1;//delete SQLite data

			rv = socket_send(&socket_info, pack_buf, buf_len);
			if(rv < 0)//ignore SIGPIPE, save data in the SQLite
			{
				log_error("write data in SQLite failure:'%s', ignore SIGPIPE, don't delete!\n", strerror(errno));
				delete_db_data = 0;
				continue;
			}
			log_debug("send data in SQLite successfully\n");

			if(delete_db_data)//write successfully, delete data in the SQLite
			{
				log_debug("now delete data already upload in the SQLite\n");

				rv = delete_1st_db(&db_info);
				if(rv < 0)
				{
					log_error("delete data failure\n");
					continue;
				}
				log_debug("delete data successfully\n");
			}
		}
	}

	close(socket_info.fd);
	sqlite3_close(db_info.db);
	return 0;
}

void alarm_handler(int signum) 
{   
	log_debug("Caught the SIGALRM signal and started sampling.\n");
	alarm_flag = 1;
	return;
}

void printf_help(char *progname )
{
    printf("%s usage:\n",progname);
    printf("-p(--port):sepcify server port\n");
    printf("-i(--ipaddr):sepcify server ip address\n");
    printf("-a(--sampling_alarm):sepcify sampling alarm time(second)\n");
    printf("-h(--help):print this help information\n");

	return;
}
